
import { Queue } from '@/lib/Queue';
import { ICall, ISerivalHooks, IStringKeyObj } from './type';
import { createStatePool } from './pool';

const callSerial = <TParam>(callList: ICall<TParam>[]) => {

  const _hooks: IStringKeyObj = {}

  const hooks: IStringKeyObj = {};
  
  ['then', 'catch', 'next',  'error'].forEach(hookName => {
    hooks[hookName] = (fn: (res: any) => void) => {
      _hooks[hookName] = fn;
      return hooks;
    }
  })

  const { start } = useQueue(callList, _hooks);
  start();

  return hooks as ISerivalHooks;
}

const useQueue = <TParam>(callList: ICall<TParam>[], _hooks: any) => {
  let queue = new Queue<ICall<TParam>>(), notConditionQueue: Queue<ICall<TParam>>, stop = false;
  queue.addAll(callList);
  const responseList: any[] = [];

  const { judgeCondition, updateState } = createStatePool();
  /**
   * 运行一次
   * @param callback 
   */
  const run = (callback: () => void | undefined) => {
    console.log('run')
    if (queue.hasElement()) {
      const call = queue.dequeue()!;
      if (judgeCondition(call?.conditions)) {
        const param = typeof call.param === 'function'?  (call.param as () => TParam)() : call.param;

        setTimeout(() => {
          call.callFunc(param).then((res) => {
            responseList.push(res);

            try {
              updateState(call.key, 'success');
              _hooks.next?.(res, call.key, {
                stopSerial,
              });
            } catch (err) {
              updateState(call.key, 'error', JSON.stringify(err));
              _hooks.error?.(err, call.key);
            }

            callback?.();
          }).catch((err) =>{
            updateState(call.key, 'warn', JSON.stringify(err));
            console.log('------Serial Promise Stop, reason：');
            console.log(err);
          })
        }, call.delay);

        
      } else {
        !notConditionQueue && (notConditionQueue = new Queue());
        notConditionQueue.enqueue(call);

        run(callback);
      }
    } else {
      console.log('队列里没有元素...')
    }
  }



  const stopSerial = () => { 
    stop = true;
  }

  const start = () => {
    if ( queue.hasElement() && !stop) {
      run(() => {
        start();
      });
    } else {
      try {
        _hooks.then?.(responseList);
      } catch (err) {
        _hooks.catch?.(err);
      }
    }
  }

  return {
    start
  };
};


export { callSerial, ICall };


